package convert

import (
	"fmt"
	"reflect"
)

// CopyValueOfSameField CopyValueOfSameField
func CopyValueOfSameField(inObj, outObj interface{}, filteFieldNames []string) {
	//
	inValue := reflect.ValueOf(inObj).Elem()
	outValue := reflect.ValueOf(outObj).Elem()
	//
	for i := 0; i < inValue.NumField(); i++ {
		fieldName := inValue.Type().Field(i).Name
		fmt.Println(fieldName)
		if IsInList(filteFieldNames, fieldName) {
			continue
		}
		methodValue := (&outValue).FieldByName(fieldName)
		value := inValue.Field(i)
		if methodValue.CanSet() {
			//field
			if value.Kind() == methodValue.Kind() {
				methodValue.Set(value)
				continue
			}
			if value.Kind().String() != "" {
				methodValue.Set(value.Addr())
				continue
			}
			if value.Elem().CanAddr() {
				methodValue.Set(value.Elem())
			}
		} else {
			//struct model
			inStructValue := value.Addr().Elem()
			for j := 0; j < inStructValue.NumField(); j++ {
				structFieldName := inStructValue.Type().Field(j).Name
				if IsInList(filteFieldNames, structFieldName) {
					continue
				}
				structMethodValue := (&outValue).FieldByName(structFieldName)
				if structMethodValue.CanSet() {
					structValue := inStructValue.Field(i)
					if structValue.Kind() == structMethodValue.Kind() {
						structMethodValue.Set(structValue)
						continue
					}
					if structValue.Kind().String() != "" {
						structMethodValue.Set(structValue.Addr())
						continue
					}
					if structValue.Elem().CanAddr() {
						structMethodValue.Set(structValue.Elem())
					}
				}
			}
		}
	}
}

// CopyValueOfSameFieldFix2 不同struct间按属性转换类型赋值 inObj  outObj 传结构体地址 ,赋值均为浅复制
func CopyValueOfSameFieldFix2(inObj, outObj interface{}, filteFieldNames []string) {
	fmt.Println(reflect.Struct)
	it := reflect.TypeOf(inObj).Elem()
	iv := reflect.ValueOf(inObj).Elem()
	ot := reflect.TypeOf(outObj).Elem()
	ov := reflect.ValueOf(outObj).Elem()
	for i := 0; i < it.NumField(); i++ {
		subiv := iv.Field(i)
		// fmt.Println("it.Field(i).Name", "\t\t\t", it.Field(i).Name)
		// fmt.Println("iv.Field(i).Interface()", "\t\t\t", iv.Field(i).Interface())
		// fmt.Println("reflect.TypeOf(iv.Field(i).Interface())", "\t\t\t", reflect.TypeOf(iv.Field(i).Interface()))
		// fmt.Println("reflect.TypeOf(it.Field(i)", "\t\t\t", it.Field(i).Type, it.Field(i).Type.String(), it.Field(i))
		// fmt.Println("reflect.TypeOf(iv.Field(i).Interface()).string", "\t\t\t", reflect.TypeOf(iv.Field(i).Interface()).String())
		// fmt.Println("iv.Field(i).Kind()", "\t\t\t", iv.Field(i).Kind())
		// fmt.Println("iv.Field(i).CanAddr()", "\t\t\t", iv.Field(i).CanAddr(), iv.Field(i).CanSet())
		// fmt.Println("iv.Field(i)..Addr().CanAddr()", "\t\t\t", iv.Field(i).Addr().CanAddr(), iv.Field(i).Addr().CanSet())
		// fmt.Println("bbbb", it.Field(i).Name, reflect.TypeOf(subiv.Addr().Interface()).Kind(), reflect.PtrTo(it.Field(i).Type).Kind())

		// fmt.Println(it.Field(i).Name, it.Field(i).Type, reflect.TypeOf(iv.Field(i).Interface()), iv.Field(i).Addr().Kind(), iv.Field(i).Kind(), reflect.TypeOf(iv.Field(i).Addr().Interface()))
		for j := 0; j < ot.NumField(); j++ {
			//subov= ov.FieldByName(it.Field(i).Name) 可以不循环对比，但要注意判空
			subov := ov.Field(j)
			if it.Field(i).Name == ot.Field(j).Name && !IsInList(filteFieldNames, it.Field(i).Name) { //字段名相同
				//结构体递归（待完善），
				if (subiv.Kind() == reflect.Struct || (subiv.Kind() == reflect.Ptr && subiv.Elem().Kind() == reflect.Struct)) && (subov.Kind() == reflect.Struct || (subov.Kind() == reflect.Ptr && subov.Elem().Kind() == reflect.Struct)) {
					// subov.Elem().Kind()  //此处*struct = nil取类型判断有问题
					sunivStruct := subiv.Addr().Interface()
					sunovStruct := subov.Addr().Interface()
					if subiv.Kind() == reflect.Ptr && subiv.Elem().Kind() == reflect.Struct {
						sunivStruct = subiv.Interface()
					}
					if subov.Kind() == reflect.Ptr && subov.Elem().Kind() == reflect.Struct {
						sunovStruct = subov.Interface()
					}
					CopyValueOfSameFieldFix2(sunivStruct, sunovStruct, filteFieldNames)
					continue
				}
				if it.Field(i).Type == ot.Field(j).Type { //比较类型
					subov.Set(subiv)
					continue
				} else if reflect.PtrTo(it.Field(i).Type) == ot.Field(j).Type { //与指针比较
					subov.Set(subiv.Addr()) //string ->*string
					// subov.Elem().Set(subiv)
					continue
				} else if it.Field(i).Type == reflect.PtrTo(ot.Field(j).Type) {
					// } else if reflect.TypeOf(iv.Field(i).Interface()) == reflect.TypeOf(ov.Field(j).Addr().Interface()) {
					subov.Set(subiv.Elem()) //*string->string
					continue
				}
				if it.Field(i).Type.AssignableTo(ot.Field(j).Type) { //还可增加对包含指针的不同类型交叉判断（未加）
					// AssignableTo 可赋值
					subov.Set(subiv.Convert(subov.Type()))
					continue
				} else if it.Field(i).Type.ConvertibleTo(ot.Field(j).Type) {
					// ConvertibleTo 可转换
					subov.Set(subiv.Convert(subov.Type()))
					continue
				}
			}
		}
	}

}
func IsInList(list []string, key string) bool {
	if list == nil {
		return false
	}
	for _, v := range list {
		if v == key {
			return true
		}
	}
	return false
}
